
// ===============================================================================================================
// -*- C++ -*-
//
// Thread.cpp - Definition of a Thread wrapper class and mutex object.
//
// This code is licenced under the MIT license.
//
// This software is provided "as is" without express or implied
// warranties. You may freely copy and compile this source into
// applications you distribute provided that the copyright text
// above is included in the resulting source code.
//
// ===============================================================================================================

#include "Thread.hpp"
#include <assert.h>

#ifdef _MSC_VER

// Win32 Threads using process.h (MSDN recommended)

unsigned int __stdcall Thread::MyThreadProc(void * ctx)
{
	Thread * threadPtr = (Thread *)ctx;
	threadPtr->userFunc(threadPtr->userData);
	_endthreadex(0);
	return (0);
}

Thread::Thread(ThreadFunc fn, void * ud) : userFunc(fn), userData(ud)
{
	unsigned int threadAddr;
	threadHandle = (void *)_beginthreadex(NULL, 0, MyThreadProc, this, 0, &threadAddr);
	assert(threadHandle != NULL);
}

void Thread::join(void)
{
	WaitForSingleObject(threadHandle, INFINITE);
}

Thread::~Thread(void)
{
	CloseHandle(threadHandle);
}

// Mutex:
Mutex::Mutex(void)
{
    BOOL result = InitializeCriticalSectionAndSpinCount(&critSect, 4096);
	assert(result);
}

Mutex::~Mutex(void)
{
    DeleteCriticalSection(&critSect);
}

void Mutex::Lock(void) const
{
    EnterCriticalSection(&critSect);
}

void Mutex::Unlock(void) const
{
    LeaveCriticalSection(&critSect);
}

#else

// POSIX PThreads

void * Thread::MyThreadProc(void * ctx)
{
	Thread * threadPtr = (Thread *)ctx;
	threadPtr->userFunc(threadPtr->userData);
	pthread_exit(NULL);
}

Thread::Thread(ThreadFunc fn, void * ud) : userFunc(fn), userData(ud)
{
	int result = pthread_create(&threadHandle, NULL, MyThreadProc, this);
	assert(result == 0);
}

void Thread::join(void)
{
	pthread_join(threadHandle, NULL);
}

Thread::~Thread(void) { }

// Mutex:
Mutex::Mutex(void)
{
	int result = pthread_mutex_init(&mtx, NULL);
	assert(result == 0);
}

Mutex::~Mutex(void)
{
	pthread_mutex_destroy(&mtx);
}

void Mutex::Lock(void) const
{
	pthread_mutex_lock(&mtx);
}

void Mutex::Unlock(void) const
{
	pthread_mutex_unlock(&mtx);
}

#endif
